from PyQt6.QtCore import QAbstractTableModel, Qt, QModelIndex, QTimer
from PyQt6.QtGui import QColor, QBrush
import time

import Global


class CustomTableModel(QAbstractTableModel):
    def __init__(self, headers=None, data=None, parent=None):
        super().__init__(parent)
        self.headers = headers or []
        self._data = data or []
        self.checked_states = {}
        self.background_colors = {}
        self.foreground_colors = {}
        self.pending_updates = {}
        self.is_updating = False
        self.first_visible_row = 0
        self.last_visible_row = 0
        self.buffer_size = 20  # 可视区域上下缓冲行数
        self.visible_data = {}  # 存储当前可视区域数据

        # 创建定时器
        from PyQt6.QtCore import QTimer
        self.update_timer = QTimer()
        self.update_timer.timeout.connect(self.applyPendingUpdates)
        self.update_timer.start(300)

    def __del__(self):
        """析构函数，清理资源"""
        if hasattr(self, 'update_timer') and self.update_timer:
            self.update_timer.stop()
            self.update_timer.timeout.disconnect()
            self.update_timer.deleteLater()

        if hasattr(self, '_wheel_timer') and self._wheel_timer:
            self._wheel_timer.stop()
            self._wheel_timer.timeout.disconnect()
            self._wheel_timer.deleteLater()
    def rowCount(self, parent=QModelIndex()):
        return len(self._data)

    def columnCount(self, parent=QModelIndex()):
        return len(self.headers)

    def data(self, index, role=Qt.ItemDataRole.DisplayRole):
        if not index.isValid():
            return None

        row = index.row()
        col = index.column()

        if role == Qt.ItemDataRole.DisplayRole:
            if col == 0:
                return str(row + 1)
            return str(self._data[row].get(self.headers[col]['key'], ''))

        if role == Qt.ItemDataRole.CheckStateRole and col == 0:
            return self.checked_states.get(row, Qt.CheckState.Unchecked)

        if role == Qt.ItemDataRole.BackgroundRole:
            # 首先检查是否有为此单元格设置的自定义背景色
            if (row, col) in self.background_colors:
                return self.background_colors[(row, col)]
            # 否则使用默认的白色背景
            return QColor(255, 255, 255)

        if role == Qt.ItemDataRole.ForegroundRole and (row, col) in self.foreground_colors:
            return self.foreground_colors[(row, col)]

        return None

    def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
        if role == Qt.ItemDataRole.DisplayRole:
            if orientation == Qt.Orientation.Horizontal:
                return self.headers[section]['name'] if section < len(self.headers) else ''
        return None

    def setData(self, index, value, role=Qt.ItemDataRole.EditRole):
        row = index.row()
        col = index.column()
        key = (row, col, role)

        # 检查值是否真的变化了
        if role == Qt.ItemDataRole.DisplayRole and col > 0:
            current_value = self.data(index, role)
            if current_value == value:
                return True

            # 如果是DisplayRole且col>0，更新实际数据
            if col < len(self.headers) and row < len(self._data):
                field_key = self.headers[col].get('key', '')
                if field_key:
                    self._data[row][field_key] = value

        # 存储更新到待处理队列
        if role == Qt.ItemDataRole.CheckStateRole and col == 0:
            self.checked_states[row] = value
            self.pending_updates[key] = (index, value, [role])
            return True
        elif role == Qt.ItemDataRole.BackgroundRole:
            self.background_colors[(row, col)] = value
            self.pending_updates[key] = (index, value, [role])
            return True
        elif role == Qt.ItemDataRole.ForegroundRole:
            self.foreground_colors[(row, col)] = value
            self.pending_updates[key] = (index, value, [role])
            return True
        elif role == Qt.ItemDataRole.DisplayRole:
            self.pending_updates[key] = (index, value, [role])
            return True

        return False

    def flags(self, index):
        flags = super().flags(index)
        if index.column() == 0:
            flags |= Qt.ItemFlag.ItemIsUserCheckable
        return flags

    def beginReset(self):
        self.beginResetModel()

    def endReset(self):
        self.endResetModel()

    def removeRows(self, row, count, parent=QModelIndex()):
        if row < 0 or row + count > len(self._data):
            return False

        self.beginRemoveRows(parent, row, row + count - 1)
        del self._data[row:row + count]
        # 更新选中状态索引
        new_checked = {}
        for k in self.checked_states:
            if k < row:
                new_checked[k] = self.checked_states[k]
            elif k >= row + count:
                new_checked[k - count] = self.checked_states[k]
        self.checked_states = new_checked
        self.endRemoveRows()
        return True

    def clear(self):
        self.beginReset()
        self._data.clear()
        self.checked_states.clear()
        self.background_colors.clear()
        self.foreground_colors.clear()
        self.pending_updates.clear()
        self.endReset()

    def loadVisibleData(self):
        """加载当前可见行的数据"""
        if not hasattr(self, 'first_visible_row') or not hasattr(self, 'last_visible_row'):
            return
            
        # 清空当前可见数据缓存
        self.visible_data.clear()
        
        # 加载新可见区域的数据
        for row in range(self.first_visible_row, self.last_visible_row + 1):
            if row < len(Global.G_Game):
                self.visible_data[row] = Global.G_Game[row].data

    def updateVisibleRows(self, first_row, last_row):
        """更新当前可见行的范围"""
        first_row = max(0, first_row - self.buffer_size)
        last_row = min(self.rowCount() - 1, last_row + self.buffer_size)

        # 只有当可见行范围确实发生变化时才更新
        if self.first_visible_row != first_row or self.last_visible_row != last_row:
            self.first_visible_row = first_row
            self.last_visible_row = last_row
            self.loadVisibleData()
            self.prioritizeVisibleRowsColorUpdate()

            # 强制触发一次数据更新，确保视图刷新
            if self.rowCount() > 0:
                top_index = self.index(first_row, 0)
                bottom_index = self.index(last_row, self.columnCount() - 1)
                self.dataChanged.emit(top_index, bottom_index, [])

    def prioritizeVisibleRowsColorUpdate(self):
        """优化可见行颜色更新逻辑，减少重绘次数"""
        if not self.pending_updates:
            return

        # 按行分组颜色更新
        row_color_updates = {}
        
        for key, (index, value, roles) in list(self.pending_updates.items()):
            row = index.row()
            if not self.isRowVisible(row):
                continue
                
            # 只处理颜色相关的更新
            color_roles = [r for r in roles if r in (Qt.ItemDataRole.BackgroundRole, Qt.ItemDataRole.ForegroundRole)]
            if not color_roles:
                continue
                
            if row not in row_color_updates:
                row_color_updates[row] = {}
                
            for role in color_roles:
                row_color_updates[row][role] = value
                
            # 移除已处理的更新
            self.pending_updates.pop(key, None)
        
        # 批量应用颜色更新
        if row_color_updates:
            for row, roles in row_color_updates.items():
                for col in range(self.columnCount()):
                    index = self.index(row, col)
                    for role, value in roles.items():
                        self.setData(index, value, role)
            
            # 触发一次更新
            self.applyPendingUpdates()

    def isRowVisible(self, row):
        """检查行是否在当前可见范围内"""
        return self.first_visible_row <= row <= self.last_visible_row

    def wheelEvent(self, event):
        """重写wheelEvent方法处理滚动事件"""
        super().wheelEvent(event)
        
        # 获取当前滚动方向
        delta = event.angleDelta().y()
        
        # 根据滚动方向动态调整缓冲区大小
        scroll_direction = 1 if delta > 0 else -1
        self.buffer_size = max(10, min(50, self.buffer_size + scroll_direction * 5))
            
        # 动态更新可见行范围
        self.updateVisibleRows(self.first_visible_row, self.last_visible_row)
        
        # 仅在滚动停止时加载数据
        if hasattr(self, '_wheel_timer'):
            self._wheel_timer.stop()
        else:
            self._wheel_timer = QTimer(self)
            self._wheel_timer.setSingleShot(True)
            self._wheel_timer.timeout.connect(self._onWheelStop)
            
        self._wheel_timer.start(200)
        
    def _onWheelStop(self):
        """滚动停止时加载数据"""
        self.loadVisibleData()
        # 重置缓冲区大小为默认值
        self.buffer_size = 20

    def applyPendingUpdates(self):
        """应用待处理的更新"""
        if not self.pending_updates or self.is_updating:
            return

        self.is_updating = True
        try:
            pending_updates_copy = dict(self.pending_updates)

            # 按行列分组更新，减少dataChanged信号的发送次数
            row_updates = {}

            for key, (index, value, roles) in pending_updates_copy.items():
                row = index.row()
                col = index.column()

                if row not in row_updates:
                    row_updates[row] = {}
                if col not in row_updates[row]:
                    row_updates[row][col] = (index, set())

                for role in roles:
                    row_updates[row][col][1].add(role)

            # 批量发送dataChanged信号
            for row, cols in row_updates.items():
                all_cols = list(cols.keys())
                if not all_cols:
                    continue

                all_cols.sort()
                start_col = all_cols[0]
                end_col = start_col
                all_roles = set()

                for col in all_cols[1:] + [None]:
                    if col is None or col > end_col + 1:
                        for c in range(start_col, end_col + 1):
                            if c in cols:
                                all_roles.update(cols[c][1])

                        start_index = self.index(row, start_col)
                        end_index = self.index(row, end_col)
                        self.dataChanged.emit(start_index, end_index, list(all_roles))

                        if col is not None:
                            start_col = col
                            end_col = col
                            all_roles = set()
                    else:
                        end_col = col

            # 清理已处理的更新
            self.pending_updates.clear()
        except Exception as e:
            print(f"表格更新过程发生异常: {str(e)}")
        finally:
            self.is_updating = False